/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package player.model;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.media.ControllerEvent;
import javax.media.ControllerListener;
import javax.media.EndOfMediaEvent;
import javax.media.Format;
import javax.media.Manager;
import javax.media.PlugInManager;
import javax.media.StartEvent;
import javax.media.Time;
import javax.media.format.AudioFormat;
import player.model.exceptions.EmptyPlaylistException;
import player.model.exceptions.NoNextTrackException;
import player.model.exceptions.NoPreviousTrackException;

/**
 *
 * @author Andrej
 */
public class PlayerImpl implements Player, ControllerListener
{
    private javax.media.Player mediaPlayer;
    private PlayerState state;
    private Playlist playlist;
    private List<PlayerObserver> observers = new ArrayList<PlayerObserver>();
    private Track track;

    /**
     * Konstruktor
     * @throws Exception greska u konstruisanju playera
     */
    public PlayerImpl() throws Exception
    {
        Format mpeg = new AudioFormat(AudioFormat.MPEG);
        AudioFormat mpeg3 = new AudioFormat(AudioFormat.MPEGLAYER3);
        AudioFormat nesto = new AudioFormat(AudioFormat.MSNAUDIO);
        Format linear = new AudioFormat(AudioFormat.LINEAR);

        PlugInManager.addPlugIn("com.sun.media.codec.audio.mp3.JavaDecoder", new Format[]{mpeg,mpeg3,nesto}, new Format[]{linear}, PlugInManager.CODEC);
        state = new StoppedState(this);

    }

    /**
     * Inicijalizuje playera
     */
    public void initPlayer()
    {
        initPlayer(track);
    }

    /**
     * Inicijalizuje player na dati track
     * @param track track
     */
    private void initPlayer(Track track)
    {
        this.track = track;
        try
        {
            mediaPlayer = Manager.createRealizedPlayer(new File(track.getFilename()).toURI().toURL());
            mediaPlayer.addControllerListener(this);

        } catch (Exception ex)
        {
            Logger.getLogger(Player.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * Vraca trenutni track
     * @return track
     */
    public Track getCurrentTrack()
    {
        return track;
    }

    /**
     * Postavlja playlistu
     * @param playlist playlista koja se postavlja
     * @throws EmptyPlaylistException greska u slucaju prazne liste
     */
    public void setPlaylist(Playlist playlist) throws EmptyPlaylistException
    {
        this.playlist = playlist;
        try
        {
            this.track = playlist.getNext();
            for(PlayerObserver observer: observers)
            {
                observer.playlistChanged();
            }
        } catch (NoNextTrackException ex)
        {
            throw new EmptyPlaylistException("Playlist is empty");
        }
        initPlayer();
    }

    /**
     * Geter playliste
     * @return trenutna playlista
     */
    public Playlist getPlaylist()
    {
        return playlist;
    }

    
    public void start() 
    {
        state.play();
    }

    public void stop()
    {
        state.stop();
    }

    public void pause()
    {
        state.pause();
    }

    public void seek(int seconds)
    {
       Time time = new Time((mediaPlayer.getDuration().getSeconds() * seconds)/track.getLenght());
       mediaPlayer.setMediaTime(time);
    }

    public int getTime()
    {
        return (int) (mediaPlayer.getTimeBase().getTime().getSeconds());
    }


    public javax.media.Player getMediaPlayer()
    {
        return mediaPlayer;
    }


    public PlayerState getState()
    {
        return state;
    }

    public void setState(PlayerState state)
    {
        this.state = state;
    }

    public void addPlayerObserver(PlayerObserver observer)
    {
        observers.add(observer);
    }

    public void removePlayerObserver(PlayerObserver observer)
    {
        observers.remove(observer);
    }

    public void playNext() throws NoNextTrackException
    {
        this.track = playlist.getNext();
        stop();

        for(PlayerObserver observer:observers)
        {
            observer.trackChanged();
        }
        start();
    }

    public void playPrevious() throws NoPreviousTrackException
    {
        this.track = playlist.getPrevious();
        stop();

        for(PlayerObserver observer:observers)
        {
            observer.trackChanged();
        }
        start();
    }

    /**
     * Metoda koja se poziva kad se kontroler updejtuje
     * @param ce event kontrolera
     */
    public void controllerUpdate(ControllerEvent ce)
    {
        if(ce instanceof EndOfMediaEvent)
        {
            try
            {
                playNext();
            } catch (Exception ex)
            {
                playbackStopped();
            }
        }
        if(ce instanceof StartEvent)
        {
            playbackStarted();
        }
    }

    /**
     * Obavjestava observere da je playback poceo
     */
    void playbackStarted()
    {
        for (PlayerObserver observer : observers)
        {
            observer.playbackStarted();
        }
    }


    /**
     * Obavjestava observere da je playback pauziran
     */
    void playbackPaused()
    {
        for (PlayerObserver observer : observers)
        {
            observer.playbackPaused();
        }
    }


    /**
     * Obavjestava observere da je playback stopiran
     */
    void playbackStopped()
    {
       for (PlayerObserver observer : observers)
        {
            observer.playbackStopped();
        }
    }

    
    public void setTrack(Track track) throws Exception
    {
        this.track = track;
        playlist.setCurrentTrack(track);
        stop();
        start();
        for(PlayerObserver observer:observers)
        {
            observer.trackChanged();
        }
    }

    public void addToPlaylist(Track track)
    {
        playlist.addTrack(track);

        for(PlayerObserver observer:observers)
        {
            observer.playlistChanged();
        }
    }
    
    public int getTrackDuration()
    {
        return (int) (mediaPlayer.getDuration().getSeconds() / mediaPlayer.getRate());
    }


    public void removeFromPlaylist(int position)
    {
        playlist.removeTrack(position);

        for(PlayerObserver observer: observers)
        {
            observer.playlistChanged();
        }
    }
   

    
}
